// Package util
// @Title util[简述该包的主要作用]
// @Description
// @Author  cnHuaShao
// @since v0.0.1
// @Version v1.0.0
// @Date 2024/4/22 22:47
// @Update 2024/4/22 22:47
package util

import (
	"errors"
	"fmt"
	"github.com/golang-jwt/jwt/v4"
	"time"
)

var (
	secretKey = []byte("fmkey") // 签名
)

// Claims
// @Description: 自定义存储逻辑
type Claims struct {
	UserId string `json:"userId"`
	jwt.RegisteredClaims
}

const TokenExpireDuration = time.Hour * 2 // 有效期

// GenToken
// @Description: 创建 Token
// @param user
// @return string
// @return error
func GenToken(userId string) (string, error) {

	// NotBefore: jwt.NewNumericDate(time.Now()),                          // 生效时间
	c := Claims{
		userId,
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenExpireDuration)), // 2小时过期
			IssuedAt:  jwt.NewNumericDate(time.Now()),                          // 签发时间
			Issuer:    "cnHuaShao",                                             // 签发人
		},
	}
	// 使用指定的签名方法创建签名对象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	// 使用指定的secret签名并获得完整的编码后的字符串token
	return token.SignedString(secretKey)
}

// ParseToken
// @Description: 解析 token
// @param tokenStr
// @return *CustomClaims
// @return error
func ParseToken(tokenStr string) (*Claims, error) {
	// 解析token
	token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return secretKey, nil
	})
	if err != nil {
		fmt.Println("令牌解析错误:", err)
		return nil, err
	}
	// 校验token
	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, nil
	}
	return nil, errors.New("invalid token")
}

// RefreshToken
// @Description: 刷新 Token
// @param tokenStr
// @return string
// @return error
func RefreshToken(tokenStr string) (string, error) {
	token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return secretKey, nil
	})
	if err != nil {
		return "", err
	}
	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		claims.RegisteredClaims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(TokenExpireDuration))
		return GenToken(claims.UserId)
	}
	return "", errors.New("couldn't handle this token")
}
